/*
 * VerbalExpressions Qt Library v0.1
 * https://github.com/VerbalExpressions/QtVerbalExpressions
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013 Skhaz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "qqtverbalexpressions.h"

#include <QDebug>

#ifdef Q_COMPILER_RVALUE_REFS
# include <utility>
#endif

QQtVerbalExpressions::QQtVerbalExpressions()
{
}

QQtVerbalExpressions::QQtVerbalExpressions ( const QQtVerbalExpressions& other )
    : prefixes ( other.prefixes )
    , m_source ( other.m_source )
    , suffixes ( other.suffixes )
    , m_pattern ( other.m_pattern )
    , modifiers ( other.modifiers )
{
}

QQtVerbalExpressions& QQtVerbalExpressions::operator= ( const QQtVerbalExpressions& other )
{
    if ( this != &other )
    {
        prefixes = other.prefixes;
        m_source = other.m_source;
        suffixes = other.suffixes;
        m_pattern = other.m_pattern;
        modifiers = other.modifiers;
    }

    return *this;
}

#ifdef Q_COMPILER_RVALUE_REFS
QQtVerbalExpressions::QQtVerbalExpressions ( const QQtVerbalExpressions&& other )
    : prefixes ( std::move ( other.prefixes ) )
    , m_source ( std::move ( other.m_source ) )
    , suffixes ( std::move ( other.suffixes ) )
    , m_pattern ( std::move ( other.m_pattern ) )
    , modifiers ( std::move ( other.modifiers ) )
{
}

QQtVerbalExpressions& QQtVerbalExpressions::operator= ( const QQtVerbalExpressions&& other )
{
    if ( this != &other )
    {
        prefixes = std::move ( other.prefixes );
        m_source = std::move ( other.m_source );
        suffixes = std::move ( other.suffixes );
        m_pattern = std::move ( other.m_pattern );
        modifiers = other.modifiers;
    }

    return *this;
}
#endif

QQtVerbalExpressions& QQtVerbalExpressions::add ( const QString& value )
{
    m_source += value;
    m_pattern = prefixes % m_source % suffixes;

    return *this;
}

QQtVerbalExpressions& QQtVerbalExpressions::startOfLine ( bool enable )
{
    prefixes = enable ? "^" : "";
    return add();
}

QQtVerbalExpressions& QQtVerbalExpressions::endOfLine ( bool enable )
{
    suffixes = enable ? "$" : "";
    return add();
}

QQtVerbalExpressions& QQtVerbalExpressions::then ( const QString& value )
{
    return add ( "(?:" % value % ")" );
}

QQtVerbalExpressions& QQtVerbalExpressions::find ( const QString& value )
{
    return then ( value );
}

QQtVerbalExpressions& QQtVerbalExpressions::maybe ( const QString& value )
{
    return add ( "(?:" % value % ")?" );
}

QQtVerbalExpressions& QQtVerbalExpressions::anything()
{
    return add ( "(?:.*)" );
}

QQtVerbalExpressions& QQtVerbalExpressions::anythingBut ( const QString& value )
{
    return add ( "(?:[^" % value % "]*)" );
}

QQtVerbalExpressions& QQtVerbalExpressions::something()
{
    return add ( "(?:.+)" );
}

QQtVerbalExpressions& QQtVerbalExpressions::somethingBut ( const QString& value )
{
    return add ( "(?:[^" % value % "]+)" );
}

QQtVerbalExpressions& QQtVerbalExpressions::lineBreak()
{
    return add ( "(?:(?:\\n)|(?:\\r\\n))" );
}

QQtVerbalExpressions& QQtVerbalExpressions::br()
{
    return lineBreak();
}

QQtVerbalExpressions& QQtVerbalExpressions::tab()
{
    return add ( "\\t" );
}

QQtVerbalExpressions& QQtVerbalExpressions::word()
{
    return add ( "\\w+" );
}

QQtVerbalExpressions& QQtVerbalExpressions::anyOf ( const QString& value )
{
    return add ( "[" % value % "]" );
}

QQtVerbalExpressions& QQtVerbalExpressions::any ( const QString& value )
{
    return anyOf ( value );
}

QQtVerbalExpressions& QQtVerbalExpressions::addModifier ( char modifier )
{
    switch ( modifier )
    {
        case 'i':
            modifiers |= QRegularExpression::CaseInsensitiveOption;
            break;

        case 'm':
            modifiers |= QRegularExpression::MultilineOption;
            break;

        case 'g':
            // TODO
            break;

        default:
            break;
    }

    return *this;
}

QQtVerbalExpressions& QQtVerbalExpressions::removeModifier ( char modifier )
{
    switch ( modifier )
    {
        case 'i':
            modifiers ^= QRegularExpression::CaseInsensitiveOption;
            break;

        case 'm':
            modifiers ^= QRegularExpression::MultilineOption;
            break;

        case 'g':
            // TODO
            break;

        default:
            break;
    }

    return *this;

}

QQtVerbalExpressions& QQtVerbalExpressions::withAnyCase ( bool enable )
{
    if ( enable )
        addModifier ( 'i' );
    else
        removeModifier ( 'i' );

    return *this;
}

QQtVerbalExpressions& QQtVerbalExpressions::searchOneLine ( bool enable )
{
    if ( enable )
        removeModifier ( 'm' );
    else
        addModifier ( 'm' );

    return *this;
}

QQtVerbalExpressions& QQtVerbalExpressions::searchGlobal ( bool enable )
{
    if ( enable )
        addModifier ( 'g' );
    else
        removeModifier ( 'g' );

    return *this;
}

QQtVerbalExpressions& QQtVerbalExpressions::multiple ( const QString& value )
{
    if ( !value.startsWith ( '*' ) || !value.startsWith ( '*' ) )
        add ( "+" );

    return add ( value );
}

QQtVerbalExpressions& QQtVerbalExpressions::alt ( const QString& value )
{
    if ( !prefixes.contains ( '(' ) )
        prefixes += '(';

    if ( !suffixes.contains ( ')' ) )
        suffixes = ')' % suffixes;

    add ( ")|(" );
    return then ( value );
}

#ifdef Q_COMPILER_INITIALIZER_LISTS
QQtVerbalExpressions& QQtVerbalExpressions::range ( const std::initializer_list<QString>& args )
{
    Q_UNUSED ( args )
    // TODO
    return *this;
}
#endif

bool QQtVerbalExpressions::test ( const QString& value )
{
    QRegularExpression re = QRegularExpression ( m_pattern, modifiers );

    // TODO
    // if (global)
    //     re.globalMatc...

    return value.contains ( re );
}

QString& QQtVerbalExpressions::replace ( QString& source, const QString& value )
{
    return source.replace ( QRegularExpression ( m_pattern ), value );
}

QDebug& operator<< ( QDebug& debug, const QQtVerbalExpressions& expression )
{
    debug << expression.pattern();
    return debug;
}

